﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace Code.Models
{
    [Serializable]
    public class NameValue<N,V>:IEnumerable<NameValueItem<N,V>>
    {
        private List<NameValueItem<N,V>> _Items;

        public NameValue()
        {
            _Items = new List<NameValueItem<N, V>>();
        }


        public V this[N p]
        {
            get
            {
                var item = this.FirstOrDefault(p1 => p1.Key.Equals(p));
                if (item == null)
                    throw new KeyNotFoundException();
                return item.Value;
            }
            set
            { 
                var item = this.FirstOrDefault(p1 => p1.Key.Equals(p));
                if (item == null)
                    throw new KeyNotFoundException();
                item.Value=value;
                
            }
        }

        public void Add(NameValueItem<N, V> item)
        {
            if (item == null)
                throw new ArgumentNullException("item");
            this._Items.Add(item);
        }

        public void Add(N name, V value)
        {
            if (name == null||(name is string && string.IsNullOrEmpty(name as string)))
                throw new ArgumentNullException("name");

            this.Add(new NameValueItem<N, V>(name,value));
        }

        public void AddRange(IEnumerable<NameValueItem<N, V>> collection)
        {
            this._Items.AddRange(collection);
        }

        public void Clear()
        {
            this._Items.Clear();
        }

        public void CopyTo(NameValueItem<N, V>[] array, int arrayIndex)
        {
            this._Items.CopyTo(array, arrayIndex);
        }

        public int Count
        {
            get { return this._Items.Count; }
        }

        public bool ContainsKey(N key)
        {
            return _Items.Select(p => p.Key).Contains(key);
        }

        public bool ContainsValue(V value)
        {
            return _Items.Select(p => p.Value).Contains(value);
        }

        public bool Remove(NameValueItem<N, V> item)
        {
            if (item == null)
                return false;
            else
                return this._Items.Remove(item);
        }


        public bool Remove(N name)
        {
            if (name == null)
                throw new ArgumentNullException("name");
            var tmp = this._Items.Where(p => p.Key.Equals(name)).FirstOrDefault();

            return this.Remove(tmp);
        }

        #region IEnumerable 成员

        IEnumerator IEnumerable.GetEnumerator()
        {
            return _Items.GetEnumerator();
        }

        #endregion

        #region IEnumerable<NameValueItem<N,V>> 成员

        IEnumerator<NameValueItem<N, V>> IEnumerable<NameValueItem<N, V>>.GetEnumerator()
        {
            return (this._Items as IEnumerable<NameValueItem<N, V>>).GetEnumerator();
        }

        #endregion
    }

    [Serializable]
    public class NameValueItem<N,V>
    {
        public N Key { get; set; }
        public V Value { get; set; }

        public NameValueItem() { }
        
        public NameValueItem(N key, V value)
        {
            this.Key = key;
            this.Value = value;
        }

        public override bool Equals(object obj)
        {
            var tp=obj as NameValueItem<N,V>;
            if (tp as object != null)
                return this.Key.Equals(tp.Key);
            else
                return base.Equals(obj);
        }

        public static bool operator == (NameValueItem<N,V> obj1,NameValueItem<N,V> obj2)
        {
            if (obj1 as object == null)
                return obj2 as object == null;
            return obj1.Equals(obj2);
        }

        public static bool operator !=(NameValueItem<N, V> obj1, NameValueItem<N, V> obj2)
        {
            if (obj1 as object == null)
                return obj2 as object != null;
            return !obj1.Equals(obj2);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
    }

    public class NameValueItemKeyEqualityComparer<N, V> : IEqualityComparer<NameValueItem<N, V>>
    {

        #region IEqualityComparer<NameValueItem<int,string>> 成员

        public bool Equals(NameValueItem<N, V> x, NameValueItem<N, V> y)
        {
            return x.Key.Equals(y.Key);
        }

        public int GetHashCode(NameValueItem<N, V> obj)
        {
            return obj.Key.GetHashCode();
        }

        #endregion
    }

    public class NameValueItemValueEqualityComparer<N, V> : IEqualityComparer<NameValueItem<N, V>>
    {

        #region IEqualityComparer<NameValueItem<int,string>> 成员

        public bool Equals(NameValueItem<N, V> x, NameValueItem<N, V> y)
        {
            return x.Value.Equals(y.Value);
        }

        public int GetHashCode(NameValueItem<N, V> obj)
        {
            return obj.Value.GetHashCode();
        }

        #endregion
    }
}